Skip to content

Fix disabled endpoints for vhosts not being reflected correctly#1190

Closed
DDH13 wants to merge 8 commits intowso2:mainfrom
DDH13:main.4234.3
Closed

Fix disabled endpoints for vhosts not being reflected correctly#1190
DDH13 wants to merge 8 commits intowso2:mainfrom
DDH13:main.4234.3

Conversation

@DDH13
Copy link
Contributor

@DDH13 DDH13 commented Oct 15, 2025

Fixes: wso2/api-manager#4234

  • Bug Fixes

    • Improved endpoint selection to correctly prefer WebSocket vs HTTP origins and avoid choosing environments without usable hosts.
    • Prevented selecting or deploying to environments that lack valid host/port combinations; gateway URLs now only build when hosts/ports are valid.
  • UX Improvements

    • Disabled server/environment selectors when none are available and show clear "No servers available"/"No valid hosts available" messaging.
    • Standardized displayed URLs and clipboard copy to use the first available/preferred URL for consistency.

Summary by CodeRabbit

Release Notes

  • New Features

    • Improved server and endpoint selection with intelligent defaults for WebSocket and HTTP connections.
  • Bug Fixes

    • Enhanced validation to prevent selecting environments with unavailable hosts or servers.
    • Improved gateway URL handling and availability logic.
  • UI/UX

    • Disabled unavailable server and environment options with informative placeholder messages.
    • Added visual feedback for invalid configurations.

✏️ Tip: You can customize this high-level summary in your review settings.

@DDH13 DDH13 marked this pull request as draft October 19, 2025 04:16
@DDH13 DDH13 marked this pull request as ready for review October 27, 2025 08:42
@coderabbitai
Copy link

coderabbitai bot commented Nov 30, 2025

Walkthrough

Adds reusable vhost and endpoint helper functions, refactors DevPortal and Publisher components to use them, and updates UI to disable or hide invalid server/host options and adapt endpoint selection logic.

Changes

Cohort / File(s) Summary
DevPortal — Async API endpoint selection
portals/devportal/src/main/webapp/source/src/app/components/Apis/Details/AsyncApiConsole/AsyncApiUI.jsx
Adds getPreferredEndpoint(URLsObj, apiType) and uses it for initial endpoint state and in a useEffect; disables Servers Select when no servers exist and adds a disabled placeholder MenuItem; adds disabled Select styling.
DevPortal — Environment URL selection
portals/devportal/src/main/webapp/source/src/app/components/Apis/Details/Environments.jsx
Adds pickFirstEnabledUrl(urls) to pick the first non-empty URL (http/https/ws/wss); replaces repeated inline URL selection and clipboard-copy logic; updates displays to use the picked URL; extends Environments.propTypes with a selectedEndpoint shape.
Publisher — Shared vhost utilities
portals/publisher/src/main/webapp/source/src/app/components/Shared/Environments/Vhosts.jsx
New helper module exporting wsDisabled, wssDisabled, hasValidWebSocketPorts, hasValidHosts, and getHostValue with defensive null checks and websocket vs non-websocket selection logic.
Publisher — Deployment VHost validation
portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Environments/DeploymentOnbording.jsx
Imports vhost helpers; uses getHostValue for default vhost selection; disables environment radio and external-gateway checkbox when hasValidHosts is false; filters vhost dropdowns by hasValidWebSocketPorts; stores host values instead of raw vhost objects.
Publisher — Environment host & gateway logic
portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Environments/Environments.jsx
Centralizes host/port checks via new helpers; replaces direct host field usage with getHostValue(vhost, isWebSocket()); prevents selecting environments without valid hosts; shows “No valid hosts available for this environment” where applicable; filters and displays vhost options by validity.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Focus areas:
    • portals/publisher/.../Environments.jsx: verify getHostValue across HTTP vs WebSocket branches and gateway URL construction.
    • DeploymentOnbording.jsx: confirm controls are correctly disabled and stored host-values match consumers.
    • AsyncApiUI.jsx and devportal Environments.jsx: review getPreferredEndpoint / pickFirstEnabledUrl behavior and useEffect updates to avoid stale state.
    • PropTypes change in devportal Environments.jsx: ensure runtime data matches the declared shape to prevent warnings.

Poem

🐇 I nibble paths and pick the best,
ws then wss, or http from the rest.
Hosts that hide I leave aside,
Disabled choices cannot ride.
A happy rabbit hops — code aligned! 🥕

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Fix disabled endpoints for vhosts not being reflected correctly' accurately describes the main change: fixing endpoint visibility and selection logic for vhosts with disabled/invalid hosts.
Linked Issues check ✅ Passed All changes align with issue #4234: centralizes endpoint/vhost selection logic, adds host validity checks to prevent selecting invalid environments, and ensures correct gateway URLs are displayed per environment.
Out of Scope Changes check ✅ Passed All changes are within scope: new vhost helper utilities, endpoint selection refactoring, disabled state UI handling, and environment validation logic directly address the linked issue.
Docstring Coverage ✅ Passed Docstring coverage is 85.71% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 96b4c22 and 1921d1a.

📒 Files selected for processing (1)
  • portals/publisher/src/main/webapp/source/src/app/components/Shared/Environments/Vhosts.jsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • portals/publisher/src/main/webapp/source/src/app/components/Shared/Environments/Vhosts.jsx

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Environments/DeploymentOnbording.jsx (1)

232-237: Default vhost selection can pick WS‑disabled vhosts for WebSocket APIs

For WS APIs, defaultVhosts always uses e.vhosts[0] via getHostValue(e.vhosts[0], api.isWebSocket()). If the first vhost has WS endpoints disabled while a later vhost has them enabled, hasValidHosts(row) will still be true (because some vhost is valid), but the default selection for that env will point at the wrong vhost and be used in createDeployRevision.

To avoid deploying a WS API to a vhost where WS is disabled, base the default host on the first vhost that actually has valid WS endpoints when api.isWebSocket() is true.

-            const defaultVhosts = selectedInternalGateways.map((e) => {
-                if (e.vhosts && e.vhosts.length > 0) {
-                    return {
-                        env: e.name,
-                        vhost: getHostValue(e.vhosts[0], api.isWebSocket()),
-                    };
-                } else {
-                    return undefined;
-                }
-            });
+            const defaultVhosts = selectedInternalGateways.map((e) => {
+                if (!e.vhosts || e.vhosts.length === 0) {
+                    return undefined;
+                }
+                const candidates = api.isWebSocket()
+                    ? e.vhosts.filter((v) => hasValidWebSocketPorts(v))
+                    : e.vhosts;
+                const first = candidates[0];
+                return first
+                    ? { env: e.name, vhost: getHostValue(first, api.isWebSocket()) }
+                    : undefined;
+            });
@@
-                const defaultVhosts = selectedExternalGateways.map((e) => {
-                    if (e.vhosts && e.vhosts.length > 0) {
-                        return {
-                            env: e.name,
-                            vhost: getHostValue(e.vhosts[0], api.isWebSocket()),
-                        };
-                    } else {
-                        return undefined;
-                    }
-                });
+                const defaultVhosts = selectedExternalGateways.map((e) => {
+                    if (!e.vhosts || e.vhosts.length === 0) {
+                        return undefined;
+                    }
+                    const candidates = api.isWebSocket()
+                        ? e.vhosts.filter((v) => hasValidWebSocketPorts(v))
+                        : e.vhosts;
+                    const first = candidates[0];
+                    return first
+                        ? { env: e.name, vhost: getHostValue(first, api.isWebSocket()) }
+                        : undefined;
+                });

Also applies to: 253-258

portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Environments/Environments.jsx (1)

608-619: Default vhost selection for WS APIs can still pick a vhost with WS disabled

As in DeploymentOnbording.jsx, defaultVhosts here always uses e.vhosts[0] and wraps it with getHostValue(e.vhosts[0], api.isWebSocket()). For WS APIs, if the first vhost has WS endpoints disabled but a later vhost has them enabled, hasValidHosts(e) will be true, yet the default selection will target the WS‑disabled vhost and be used in deployments.

This undermines the intent of the new validity checks.

Refine the default selection to prefer a vhost with valid WS endpoints for WS APIs:

-                const defaultVhosts = selectedInternalGateways.map((e) => {
-                    if (e.vhosts && e.vhosts.length > 0) {
-                        return {
-                            env: e.name,
-                            vhost: getHostValue(e.vhosts[0], api.isWebSocket())
-                        };
-                    } else {
-                        return undefined;
-                    }
-                });
+                const defaultVhosts = selectedInternalGateways.map((e) => {
+                    if (!e.vhosts || e.vhosts.length === 0) {
+                        return undefined;
+                    }
+                    const candidates = api.isWebSocket()
+                        ? e.vhosts.filter((v) => hasValidWebSocketPorts(v))
+                        : e.vhosts;
+                    const first = candidates[0];
+                    return first
+                        ? { env: e.name, vhost: getHostValue(first, api.isWebSocket()) }
+                        : undefined;
+                });
@@
-                    const defaultVhosts = selectedExternalGateways.map((e) => {
-                        if (e.vhosts && e.vhosts.length > 0) {
-                            return {
-                                env: e.name,
-                                vhost: getHostValue(e.vhosts[0], api.isWebSocket())
-                            };
-                        } else {
-                            return undefined;
-                        }
-                    });
+                    const defaultVhosts = selectedExternalGateways.map((e) => {
+                        if (!e.vhosts || e.vhosts.length === 0) {
+                            return undefined;
+                        }
+                        const candidates = api.isWebSocket()
+                            ? e.vhosts.filter((v) => hasValidWebSocketPorts(v))
+                            : e.vhosts;
+                        const first = candidates[0];
+                        return first
+                            ? { env: e.name, vhost: getHostValue(first, api.isWebSocket()) }
+                            : undefined;
+                    });

This keeps default behavior unchanged for HTTP APIs, while ensuring WS APIs default to a vhost where WS is actually enabled.

Also applies to: 631-642

🧹 Nitpick comments (5)
portals/devportal/src/main/webapp/source/src/app/components/Apis/Details/AsyncApiConsole/AsyncApiUI.jsx (2)

57-62: Disabled styling looks fine; consider using theme palette for consistency

The .Mui-disabled styling on the Select matches the intended UX and is scoped correctly to .selectList. If you want this to stay in sync with the app theme, you could optionally refactor Root to take ({ theme }) and use theme.palette.action.disabledBackground / theme.palette.text.disabled instead of hard‑coded colors, but it’s not required for this PR.


78-90: Centralized endpoint selection is good; double‑check preference for insecure vs secure URLs

getPreferredEndpoint nicely centralizes the initial endpoint selection and the useEffect keeps endPoint in sync when URLs or api.type change, which is a clear improvement.

One thing to verify: the helper prefers non‑secure schemes when both are present:

  • For WS APIs, it picks ws first and only falls back to wss.
  • For non‑WS APIs, it picks http first and only falls back to https.

If both secure and insecure endpoints are configured, this will always pick the insecure one. That may be intentional (e.g., for local/dev usage), but if the desired behavior is to prefer secure endpoints when available, you may want to invert the order:

-  if (apiType === CONSTANTS.API_TYPES.WS) {
-    // prefer ws, but if ws does not exist fall back to wss
-    if (URLsObj.ws) return URLsObj.ws;
-    if (URLsObj.wss) return URLsObj.wss;
+  if (apiType === CONSTANTS.API_TYPES.WS) {
+    // Prefer secure wss, fall back to ws if wss is not available
+    if (URLsObj.wss) return URLsObj.wss;
+    if (URLsObj.ws) return URLsObj.ws;
   }
-  // for non-WS APIs prefer http, but if http does not exist fall back to https
-  if (URLsObj.http) return URLsObj.http;
-  if (URLsObj.https) return URLsObj.https;
+  // For non-WS APIs prefer https, fall back to http if https is not available
+  if (URLsObj.https) return URLsObj.https;
+  if (URLsObj.http) return URLsObj.http;

Please confirm which ordering matches the product expectation before changing.

Also applies to: 92-92, 103-105

portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Environments/DeploymentOnbording.jsx (1)

175-195: Shared WS/host helper logic looks good, but consider centralizing

The wsDisabled/wssDisabled/hasValidWebSocketPorts/hasValidHosts/getHostValue helpers are clean and match those in Environments.jsx, which is good for consistency. Given they are duplicated across components, consider extracting them into a shared utility to avoid drift on future changes.

portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Environments/Environments.jsx (2)

550-574: WS/host helper set is consistent and readable

The wsDisabled/wssDisabled/hasValidWebSocketPorts/hasValidHosts/getHostValue helpers cleanly encapsulate WS vs HTTP host/port validity and selection, and they align with the same logic reused in DeploymentOnbording.jsx.

Consider moving these helpers to a shared module so Environments.jsx and DeploymentOnbording.jsx can import them from a single place.


2551-2555: getVhostHelperText and tooltips now communicate host availability clearly

The WS branch of getVhostHelperText correctly resolves the selected vhost via wsHost/wssHost and returns a clear “No valid hosts available for this environment” message when WS endpoints are disabled on that vhost. Combined with the updated tooltips that fall back to that message when !hasValidHosts(row), this should make host availability much more transparent to users.

Also applies to: 2568-2574, 3567-3575, 3795-3803

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4756152 and 1f223ed.

📒 Files selected for processing (4)
  • portals/devportal/src/main/webapp/source/src/app/components/Apis/Details/AsyncApiConsole/AsyncApiUI.jsx (4 hunks)
  • portals/devportal/src/main/webapp/source/src/app/components/Apis/Details/Environments.jsx (10 hunks)
  • portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Environments/DeploymentOnbording.jsx (7 hunks)
  • portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Environments/Environments.jsx (18 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
portals/devportal/src/main/webapp/source/src/app/components/Apis/Details/AsyncApiConsole/AsyncApiUI.jsx (1)
portals/devportal/src/main/webapp/source/src/app/components/Apis/Details/AsyncApiConsole/AsyncApiConsole.jsx (1)
  • URLs (91-91)
portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Environments/DeploymentOnbording.jsx (1)
portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Environments/Environments.jsx (5)
  • wsDisabled (550-550)
  • wssDisabled (551-551)
  • hasValidWebSocketPorts (553-555)
  • hasValidHosts (557-563)
  • getHostValue (566-574)
🔇 Additional comments (5)
portals/devportal/src/main/webapp/source/src/app/components/Apis/Details/AsyncApiConsole/AsyncApiUI.jsx (1)

245-245: Guard against falsy URLs when using Object.keys/Object.values

The disable logic assumes URLs is always a non‑null object:

disabled={Object.keys(URLs).length === 0 || !Object.values(URLs).some(Boolean)}
{Object.keys(URLs).length === 0 || !Object.values(URLs).some(Boolean) ? ( ... )}

If URLs transitions to null/undefined during async environment loading, Object.keys() and Object.values() will throw. Add a falsy check:

-disabled={Object.keys(URLs).length === 0 || !Object.values(URLs).some(Boolean)}
+disabled={!URLs || Object.keys(URLs).length === 0 || !Object.values(URLs).some(Boolean)}

Additionally, if URLs can contain non-string values (e.g., nested objects or metadata), the MenuItems will render as [object Object]. Filter to string values only:

Object.entries(URLs)
  .filter(([, value]) => typeof value === 'string' && value)
  .map(([key, value]) => (
    <MenuItem value={value} key={key}>{value}</MenuItem>
  ));

Applies to lines 245 and 248–259.

portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Environments/DeploymentOnbording.jsx (1)

459-460: Host validity checks and vhost dropdown filtering are aligned with WS semantics

Disabling environment selection (Checkbox) and the vhost TextField when !hasValidHosts(row), and filtering vhosts for WS APIs via hasValidWebSocketPorts(vhost) before mapping to MenuItems, correctly prevents choosing vhosts with WS endpoints disabled. Using getHostValue for both key and value keeps the stored value consistent for HTTP vs WS cases.

Also applies to: 550-565, 684-686, 748-762

portals/devportal/src/main/webapp/source/src/app/components/Apis/Details/Environments.jsx (2)

121-130: pickFirstEnabledUrl helper is simple and robust

The helper defensively handles missing/invalid urls and cleanly picks the first non-empty string, which keeps the call sites concise.


502-518: selectedEndpoint propTypes shape is now explicit and matches usage

The new selectedEndpoint shape (environmentName/Type plus nested URLs and defaultVersionURLs) matches how the component reads these fields and should help catch mismatches at runtime.

portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Environments/Environments.jsx (1)

795-803: Guard in handleChange correctly prevents selecting environments without valid hosts

The early return when event.target.checked && environment && !hasValidHosts(environment) prevents adding environments that have no valid hosts for the current API type into SelectedEnvironment, which complements the UI disabled states. This is a good safety net around the selection logic.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Environments/DeploymentOnbording.jsx (1)

215-241: For WS APIs, default vhost should prefer the first WS‑valid vhost, not always index 0

You now store host strings via getHostValue(e.vhosts[0], api.isWebSocket()). For WebSocket APIs this still blindly uses the first vhost even if it has WS endpoints disabled while a later vhost is WS‑enabled. In that case:

  • hasValidHosts(row, api.isWebSocket()) will enable the environment (because at least one vhost is valid),
  • but selectedVhostDeploy will still hold the disabled vhost’s host value until the user manually changes it.

Safer to choose the first WS‑valid vhost when api.isWebSocket():

-            const defaultVhosts = selectedInternalGateways.map((e) => {
-                if (e.vhosts && e.vhosts.length > 0) {
-                    return {
-                        env: e.name,
-                        vhost: getHostValue(e.vhosts[0], api.isWebSocket()),
-                    };
-                } else {
-                    return undefined;
-                }
-            });
+            const defaultVhosts = selectedInternalGateways.map((e) => {
+                if (!e.vhosts || e.vhosts.length === 0) {
+                    return undefined;
+                }
+                const baseVhost = api.isWebSocket()
+                    ? (e.vhosts.find((v) => hasValidWebSocketPorts(v)) || e.vhosts[0])
+                    : e.vhosts[0];
+                return {
+                    env: e.name,
+                    vhost: getHostValue(baseVhost, api.isWebSocket()),
+                };
+            });

Apply the same pattern in the external‑gateway branch below for consistency.

portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Environments/Environments.jsx (1)

590-600: Mirror “choose first WS‑valid vhost” here for consistency with onboarding

As in DeploymentOnbording.jsx, default vhosts for each environment are still based on e.vhosts[0], now wrapped in getHostValue. For WS APIs this can select a WS‑disabled vhost even when a later vhost is WS‑enabled, leaving selectedVhosts/selectedVhostDeploy pointing at a disabled host until the user changes it.

To keep defaults aligned with your new validity helpers and avoid that subtle mismatch, consider:

-                const defaultVhosts = selectedInternalGateways.map((e) => {
-                    if (e.vhosts && e.vhosts.length > 0) {
-                        return {
-                            env: e.name,
-                            vhost: getHostValue(e.vhosts[0], api.isWebSocket())
-                        };
-                    } else {
-                        return undefined;
-                    }
-                });
+                const defaultVhosts = selectedInternalGateways.map((e) => {
+                    if (!e.vhosts || e.vhosts.length === 0) {
+                        return undefined;
+                    }
+                    const baseVhost = api.isWebSocket()
+                        ? (e.vhosts.find((v) => hasValidWebSocketPorts(v)) || e.vhosts[0])
+                        : e.vhosts[0];
+                    return {
+                        env: e.name,
+                        vhost: getHostValue(baseVhost, api.isWebSocket()),
+                    };
+                });

and similarly in the external‑gateway branch below.

Also applies to: 613-625

♻️ Duplicate comments (3)
portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Environments/Environments.jsx (3)

3161-3170: External gateways in deploy‑new‑revision now use getHostValue consistently

The external gateways’ vhost dropdown now derives key/value/label via getHostValue(vhost, api.isWebSocket()), so HTTP vs WS host selection is centralized and consistent with internal gateways and other views.

Given earlier discussion that fully filtering out WS‑disabled vhosts in some edge‑case UIs is acceptable to skip, leaving this menu unfiltered and just normalizing the host values is reasonable.


3551-3603: Internal “Select Access URL” dropdown: tooltip/disabled state respect host validity, options normalized

For internal gateways with no deployed revision:

  • Tooltip now shows either the usual helper text or a clear 'No valid hosts available for this environment' when hasValidHosts(row, api.isWebSocket()) is false.
  • The vhost selector gets disabled under the same condition, preventing WS APIs from picking a vhost in envs that have no WS‑capable hosts at all.
  • Option values are now generated via getHostValue, so the selected value matches the same host string used everywhere else.

Previously raised concerns about additionally filtering out WS‑disabled vhosts in this dropdown were discussed and accepted as an edge case; the current normalization is consistent with that decision.


3779-3827: External “Select Access URL” dropdown mirrors internal behavior and uses getHostValue

The external gateways table now:

  • Uses the same “No valid hosts available for this environment” tooltip when hasValidHosts(row, api.isWebSocket()) is false.
  • Disables the vhost selector under that condition.
  • Normalizes option values/labels via getHostValue(vhost, api.isWebSocket()).

That brings external gateways in line with internal ones while preserving the earlier choice not to hard‑filter WS‑disabled vhosts in this particular view.

🧹 Nitpick comments (3)
portals/publisher/src/main/webapp/source/src/app/components/Shared/Environments/Vhosts.jsx (1)

34-55: Host validity / selection helpers look consistent with API‑type semantics

hasValidHosts only enforces WebSocket vhost validity when isWebSocket === true, leaving HTTP and GraphQL APIs to accept any defined vhost, which matches typical expectations (HTTP always available; WS is only mandatory for pure WS APIs). getHostValue’s “prefer wsHost, fall back to wssHost when ws is disabled” is internally consistent with how you filter vhosts elsewhere.

If, in future, you decide secure WS (wssHost) should be preferred when both WS/WSS are enabled, this is the single place to flip that policy. For now, the current behavior is coherent with the rest of the PR.

portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Environments/Environments.jsx (2)

777-795: Env selection short‑circuit on invalid hosts is safe but slightly redundant

The new check in handleChange:

const environment = settings.environment.find((env) => env.name === event.target.value);
if (event.target.checked && environment && !hasValidHosts(environment, api.isWebSocket())) {
    return;
}

correctly prevents adding environments that don’t have any valid hosts for a WS API, even if something went wrong with disabled props. It’s a harmless extra guard, and the event.target.checked predicate ensures text fields (like description) are unaffected.


2526-2556: getVhostHelperText WS/shortened output is improved; will benefit from the null‑guard on hasValidWebSocketPorts

Changes here:

  • For WS APIs, you now resolve the underlying vhost via wsHost/wssHost and short‑circuit with 'No valid hosts available for this environment' when hasValidWebSocketPorts(vhost) is false.
  • In shorten mode you compute a single preferred URL (secondary || primary) and truncate it, rather than showing the concatenated combined string, which is clearer.
  • GraphQL handling (HTTP + WS URLs) remains intact and only applies when not shortening.

Once hasValidWebSocketPorts treats null/undefined as “no valid ports” (see earlier comment), this helper will also behave sensibly if a selection ever points at a non‑existent vhost.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 08472b7 and 96b4c22.

📒 Files selected for processing (3)
  • portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Environments/DeploymentOnbording.jsx (7 hunks)
  • portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Environments/Environments.jsx (18 hunks)
  • portals/publisher/src/main/webapp/source/src/app/components/Shared/Environments/Vhosts.jsx (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-08T04:10:03.206Z
Learnt from: DDH13
Repo: wso2/apim-apps PR: 1190
File: portals/devportal/src/main/webapp/source/src/app/components/Apis/Details/Environments.jsx:140-152
Timestamp: 2025-12-08T04:10:03.206Z
Learning: For WSO2 APIM devportal, the backend populates selectedEndpoint.URLs based on API type: HTTP APIs have only http/https populated (ws/wss are null), WebSocket APIs have only ws/wss populated (http/https are null), and GraphQL APIs have all four protocols (http, https, ws, wss) populated.

Applied to files:

  • portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Environments/Environments.jsx
🧬 Code graph analysis (2)
portals/publisher/src/main/webapp/source/src/app/components/Shared/Environments/Vhosts.jsx (2)
portals/devportal/src/main/webapp/source/src/app/components/Applications/Details/Overview.jsx (1)
  • environment (204-204)
portals/publisher/src/main/webapp/source/src/app/components/Apis/Create/StreamingAPI/APICreateStreamingAPI.jsx (1)
  • isWebSocket (79-79)
portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Environments/DeploymentOnbording.jsx (1)
portals/publisher/src/main/webapp/source/src/app/components/Shared/Environments/Vhosts.jsx (6)
  • getHostValue (47-55)
  • getHostValue (47-55)
  • hasValidHosts (34-39)
  • hasValidHosts (34-39)
  • hasValidWebSocketPorts (24-26)
  • hasValidWebSocketPorts (24-26)
🔇 Additional comments (6)
portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Environments/DeploymentOnbording.jsx (2)

419-451: WS vhost filtering and env disabling are wired correctly

  • Internal gateway checkbox: disabled={!hasValidHosts(row, api.isWebSocket())} cleanly blocks selecting environments that have no WS‑capable vhost for WS APIs while remaining a no‑op for HTTP/GraphQL.
  • Internal and external vhost dropdowns now filter with hasValidWebSocketPorts when api.isWebSocket() and use getHostValue for key/value/display, so WS APIs cannot pick a WS‑disabled vhost from these menus.

This aligns with the PR’s objective of reflecting disabled endpoints in the UI and centralizes the logic through the shared helpers.

Also applies to: 484-549


663-669: External gateway checkbox + dropdown behavior is consistent and safe

The external gateway checkbox is now disabled when either deployments are restricted or !hasValidHosts(row, api.isWebSocket()), and the vhost dropdown options for WS APIs are filtered by hasValidWebSocketPorts with host values derived via getHostValue.

That keeps WS selection consistent between internal and external gateways and prevents choosing WS‑disabled vhosts through this onboarding flow.

Also applies to: 706-747

portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Environments/Environments.jsx (4)

77-83: Centralized VHost helper imports are appropriate

Importing wsDisabled, wssDisabled, hasValidWebSocketPorts, hasValidHosts, and getHostValue here keeps the environment logic consistent with the shared helpers and avoids duplicating WS/HTTP host rules in this large component.


2116-2145: WS URL generation now respects disabled WS/WSS endpoints

The getGatewayAccessUrl WS branch now only builds ws:// and wss:// URLs when wsDisabled(vhost) / wssDisabled(vhost) are false. That prevents bogus ws://null:null/wss://null:null URLs from appearing when an endpoint is disabled, while still returning empty strings for missing variants.

Combined with your validation helpers, this should give more accurate Gateway Access URLs in the tables and helper text.


2184-2188: Revision selection correctly gated on host validity

Both “no revision yet” and “some revisions available” flows now disable the revision <TextField> when !hasValidHosts(row, api.isWebSocket()). This:

  • Blocks deploy attempts for WS APIs on environments with no WS‑capable vhosts.
  • Leaves HTTP/GraphQL behavior unchanged (any env with vhosts remains selectable).

That’s consistent with the rest of your host validation and the PR goal.

Also applies to: 2298-2302


2894-2896: Deploy‑new‑revision internal gateway card: WS validation and option list look good

Inside the deploy‑new‑revision dialog:

  • The internal gateway checkbox is now disabled when !hasValidHosts(row, api.isWebSocket()), mirroring the main environments list and preventing WS APIs from targeting envs without WS‑capable vhosts.
  • The vhost selector is disabled under the same condition and its options are filtered by hasValidWebSocketPorts for WS APIs, with display/value coming from getHostValue.

This keeps the dialog behavior aligned with the onboarding component and ensures WS‑disabled vhosts can’t be selected here.

Also applies to: 2972-2995

@sonarqubecloud
Copy link

sonarqubecloud bot commented Dec 8, 2025

Quality Gate Failed Quality Gate failed

Failed conditions
6.2% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@DDH13 DDH13 closed this Dec 10, 2025
YasasRangika pushed a commit to YasasRangika/apim-apps that referenced this pull request Dec 18, 2025
YasasRangika pushed a commit to YasasRangika/apim-apps that referenced this pull request Dec 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Gateway environment urls are not being reflected accurately for WebSocket APIs

1 participant